package com.tbynet.jwp.framework.kit;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

/**
 * 加密方式
 * @ClassName: PassKit
 * @Description: 模仿wordpress加密方式
 * 第一段：$P$格式固定 
 * 第二段：只有一个字符。若php版本大于5.0则为B，否则为9 
 * 第三段：8位salt （随机数）
 * 第四段：22位，真正加密后的密码
 * @Author: 佰亿互联
 * @Date: 2019年3月22日 上午1:30:41
 * 
 * @Copyright: 2019 www.tbynet.com Inc. All rights reserved.
 * 注意: 本内容仅限于内部传阅，禁止外泄以及用于其他的商业目
 */
public class PassKit {

	public static void main(String[] args) throws NoSuchAlgorithmException {
		//$P$BIslEv.XMtgd8n9lsPZRGPxnHO8n2k1
		//System.out.println(encrypt("xxxxxx", "IslEv.XM"));
		System.out.println(getSalt("$P$BIslEv.XMtgd8n9lsPZRGPxnHO8n2k1"));
	}
	
	public static String encrypt(String str) {
		return encrypt(str, getSalt());
	}
	
	public static String encrypt(String str, String salt) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
			byte[] hash = md.digest((salt + str).getBytes());
			byte[] palin = str.getBytes();		//密码
			for (int i = 0; i < 8192; i++) {
				byte[] newplain = new byte[hash.length + palin.length];
				/*
				 * 要复制的数组；从那里开始复制；复制到那个数组；从那里开始；复制多长
				 */
				System.arraycopy(hash, 0, newplain, 0, hash.length);
				System.arraycopy(palin, 0, newplain, hash.length, palin.length);
				//md5加密
				MessageDigest md5 = MessageDigest.getInstance("MD5");
				//digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
				//BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
				hash = md5.digest(newplain);
			}
			int[] x = new int[hash.length];
			for (int i = 0; i < hash.length; i++) {
				x[i] = hash[i] & 0xff;
			}
			return "$P$B" + salt + encode64(x, 16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return "fail";
		}
	}
	
	public static String getSalt() {
		int maxNum = 36;
		int i;
		int count = 0;
		char[] str = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
		    'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
		    'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };	  
		StringBuilder salt = new StringBuilder();
		Random r = new Random();
		while(count < 8){
		   i = Math.abs(r.nextInt(maxNum));   
		   if (i >= 0 && i < str.length) {
			   salt.append(str[i]);
			   count ++;
		   }
		}
		return salt.toString();
	}
	
	//$P$BIslEv.XM
	public static String getSalt(String str) {
		return str.substring(4, 12);
	}

//	1，获得一个hash ，是一个byte[]类型。这个hash是明文密码（pass）和salt的md5加密
//	2，将明文密码转换为byte[]
//	3，运行2的13次方循环，即8192次循环，循环内容如下
//	    3.1，创建一个新的byte[]，我们叫他为newbyte，他的长度是上面1和2两个长度之和
//	    3.2，将上面1的数组（也就是hash）复制到这个新的newbyte
//	    3.3，将上面2的数组（明文密码转换的byte[]）继续复制到这个新的newbyte
//	    3.4，将这个新的数组进行一次md5计算，得到一个新值，把这个值给hash
//	    3.5，如此循环，也就是说每次新的newbyte，他的前面部分是变化的，后面部分没有没有
//	4，最终得到一个新的newhash1，与0xff进行与运算
//	5，最后返回我们最终的密码
	
	private static String encode64(int[] input, int number) {
		String hash = "";
		int output = 0;
		int[] input_2 = new int[number];
		for (int i = 0; i < number; i++) {
			input_2[i] = input[i];
		}
		
		String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
		int output_2 = 0;
		int value_2 = 0;
		for (int i = 0; i < number; i++) {
			int value = input_2[i];
			output = input_2[i];
			hash += itoa64.substring((value % 64 + 64) % 64, (value % 64 + 64) % 64 + 1);
			if (i + 1 <= number) {
				if (i + 1 < number) {
					value = input_2[++i];
					output_2 = (value << 8);		//左移8位
					output = output + output_2;
				}
				
				value_2 = output;
				int len = Integer.toBinaryString(output).length();
				
				if (len - 6 > 0) {
					output = (output >> 6);			//右移6位
				} else {
					output = 0;
				}
				
				value = output;
				hash += itoa64.substring((value % 64 + 64) % 64, (value % 64 + 64) % 64 + 1);
			} else {
				break;
			}
			
			if (i + 1 < number) {
				value = input_2[++i];
				output_2 = (value << 16);			//左移16位
				output = value_2 + output_2;
				value_2 = output;
				output_2 = output;
				output = (output >> 12);			//右移12位
				value = output;
				hash += itoa64.substring((value % 64 + 64) % 64, (value % 64 + 64) % 64 + 1);
			} else {
				break;
			}
			
			if (i + 1 < number) {
				output = (output_2 >> 18);			//右移18位
				value = output;
				hash += itoa64.substring((value % 64 + 64) % 64, (value % 64 + 64) % 64 + 1);
			}
		}
		return hash;
	}

}
